package require logger
#-- package require logger::appender
set logger [logger::init harness]
#-- logger::appender::colorConsole -level debug -service harness
logger::import -namespace logger harness


#-----------------------------------------------
# harness
#-----------------------------------------------

namespace eval harness {
    variable TEST_EXEC
    variable TEST_PATH
    variable LOCAL_HOME
    variable TEST_FILE

    variable cp_list [list ]
    variable current_view "i"
    variable current_cp   "default"

    namespace eval meta { }

    proc init {test_file view} {
        variable TEST_FILE $test_file
	set cp_list [list ]
	set current_view $view
	set current_cp "default"
    }
}


#-- proc harness::assert { args } {
#--     set expression $args
#--     logger::debug "expression = $expression"
#--     set rv [eval expr $expression]
#--     if $rv {
#--         logger::notice "ASSERTION PASS: {$expression} "
#--     } else {
#--         logger::warn   "ASSERTION FAIL: {$expression} "
#--     }
#-- }




#------------------------------------------------
# namespace harness::meta
#------------------------------------------------

namespace eval harness::meta {
    variable cp_list [list ]
    variable current_view "i"
    variable current_file "/dev/null"
    variable current_cp   "default"
    variable fp_map
    variable iomux

    variable context

    variable i:/sandbox/
    variable r:/sandbox/
}

proc harness::meta::_trace_enter {cmd op} {
    logger::debug "#cp> $cmd"
}

proc harness::meta::_trace_leave {cmd code result op} {
    logger::debug "#cp>--- $cmd"
}

proc harness::meta::trace {} {
    #set commands [info commands harness::meta::*]
    ::trace add execution harness::meta::assert enter _trace_enter
    ::trace add execution harness::meta::assert leave _trace_leave
    ::trace add execution harness::meta::mkcp enter harness::meta::_trace_enter
    ::trace add execution harness::meta::excp enter harness::meta::_trace_enter
}

proc harness::meta::init {view file} {
    variable cp_list [list ]
    variable current_view $view
    variable current_file $file
    variable current_cp   "default"
    variable fp_map
    variable iomux
    set current_view $view
    array set fp_map [list]
    set iomux [iomux::init meta]
}

proc harness::meta::puts {line} {
    variable iomux
    ${iomux}::puts $line
    return
}

proc harness::meta::mkcp {cp_name} {
    variable current_cp
    variable cp_list
    variable fp_map
    variable iomux
    #-- logger::debug "mkcp $cp_name"
    set current_cp $cp_name
    lappend cp_list $current_cp
    set file [current_cp_file]
    set fp_ [open $file a]
    set cp $cp_name
    #TODO: logger::debug "---> $cp $file $fp_"
    array set fp_map [list $file $fp_]
    ${iomux}::mk_pipe $fp_
    return $current_cp
}

proc harness::meta::excp {cp_name} {
    variable cp_list
    variable current_cp
    variable fp_map
    variable iomux
    #-- logger::debug "excp $cp_name"
    set i [lsearch $cp_list $cp_name]
    if {$i < 0} {
    }
    set cp [lindex $cp_list $i]
    set cp_list [lreplace $cp_list $i $i]
    set current_cp [lindex $cp_list end]
    set file [harness::meta::current_cp_file $cp]
    set fp_ [lindex [array get fp_map $file] 1]
    #TODO: logger::debug "<---- $cp $file $fp_"
    ${iomux}::rm_pipe $fp_
    close $fp_
    return $cp
}

proc harness::meta::current_cp {} {
    variable current_cp
    return $current_cp
}

proc harness::meta::current_cp_file {{cp ""}} {
    variable current_cp
    variable current_view
    if {$cp == ""} { set cp $current_cp}
    return [get_cp_file $current_view $cp]
}

proc harness::meta::get_cp_file {{view ""} {cp ""}} {
    variable current_cp
    variable current_view
    if {$cp == ""} { set cp $current_cp}
    if {$view == ""} { set view $current_view }
    return "cp.$cp.$view"
}

proc harness::meta::get_sandbox_file {{view ""} {file ""}} {
    variable current_cp
    variable current_view

    variable context

    if {$view == ""} { set view $current_view }

    set sandbox [lindex [array get context $view:sandbox] 1]
    return [file join $sandbox $file]
}

proc harness::meta::context { action args } {
    variable context

    if {$action == "get" } {
        return [lindex [array get context [lindex $args 0]] 1]
    } elseif {$action == "set" } {
        array set context $args
    }
}

proc harness::meta::assert { args } {
    set expression $args
    #TODO: logger::debug "expression = $expression"
    set rv [eval expr $expression]
    if $rv {
        #TODO: logger::notice "ASSERTION PASS: {$expression} "
        return true
    } else {
        #TODO: logger::warn   "ASSERTION FAIL: {$expression} "
        return false
    }
}

proc harness::meta::exec {args} {
    set status 0
    if {[catch {uplevel eval ::exec $args} results]} {
       if {[lindex $::errorCode 0] == "CHILDSTATUS"} {
          set status [lindex $::errorCode 2]
       } else {
          # Some kind of unexpected failure
          set status 255
       }
       #TODO: logger::warn $::errorCode
       #TODO: logger::warn $results
       #logger::warn $::errorCode
       #logger::warn $results
    }
    return $status
}

proc harness::meta::filter_proc_args {argv} {
    set index [lsearch -all -exact $argv $ ]
    set rv [list ]
    foreach arg $argv {
        set v $arg
        if [regexp {^(i|r):/CP/(\w*)} $arg matched view cp] {
	    set v [get_cp_file $view $cp]
        } elseif [regexp {^(i|r):/sandbox/(\S+)} $arg matched view file] {
	    set v [get_sandbox_file $view $file]
        }
        lappend rv $v
    }
    return $rv
}
#---------------------------------------------------
# grep/egrep
#---------------------------------------------------
# grep -i
# grep -v
# grep -c 3
# grep -m 3
#---------------------------------------------------

proc harness::meta::grep {args} {
    set args [filter_proc_args $args]
    set rv [::harness::meta::exec grep $args]
    return [expr $rv == 0]
}

proc harness::meta::meta_hello {args} {
    #TODO: logger::debug "Exec meta_hello: $args"
    return true
}

#---------------------------------------------------
# parse_log
#---------------------------------------------------

proc parse_log_bak {view file} {
    logger::info "------------- Parse  -------------"
    set fp [open $file]
    set assert.tcl $file.assert
    set fp_assert [open $view.assert w]
    array set fp_map [list ]
    iomux::init
    harness::meta::init $view $file
    set buffer [list ]
    while {[gets $fp line] >= 0} {
        set magic [lindex $line 0]
        set cmd   [lindex $line 1]
        set cmd_args [lrange $line 2 end]
        # process text line
        if {$magic != "#cp>"} { 
            iomux::puts $line 
            continue
        }
        regsub {#cp>\s+} $line "" cmd_line 
        puts $fp_assert $cmd_line
        # process cp line
        switch $cmd {
            {mkcp}  {
                set cp [harness::meta::mkcp [lindex $cmd_args 0]]
                set file [harness::meta::current_cp_file]
                set fp_ [open $file a]
                logger::debug "---> $cp $file $fp_"
                array set fp_map [list $file $fp_]
                iomux::mk_pipe $fp_
            }
            {excp}  {
                set cp [harness::meta::excp [lindex $cmd_args 0]]
                set file [harness::meta::current_cp_file $cp]
                set fp_ [lindex [array get fp_map $file] 1]
                logger::debug "<---- $cp $file $fp_"
                iomux::rm_pipe $fp_
                close $fp_
            }
        }
    }
    close $fp
    close $fp_assert
    logger::info "------------- Assert -------------"
    set harness::meta::assert_tcl ${assert.tcl}
    harness::meta::trace
    namespace eval harness::meta {source $assert_tcl}
}



proc parse_log {view file} {
    logger::info "------------- Parse  -------------"
    set fp [open $file]
    set assert.tcl $file.assert
    set fp_assert [open $view.assert w]
    array set fp_map [list ]
    set iomux [iomux::init parse_log "\t"]
    ${iomux}::mk_pipe stdout
    harness::meta::init $view $file
    #-- harness::meta::trace
    set buffer [list ]
    while {[gets $fp line] >= 0} {
        set magic [lindex $line 0]
        set cmd   [lindex $line 1]
        set cmd_args [lrange $line 2 end]
        # process text line
        if {![regexp {^(#cp>|#cp%)} $line magic]} {
            #iomux::puts $line 
	    namespace eval harness::meta [list harness::meta::puts $line]
            continue
        }

        regsub {^(#cp>|#cp%) } $line "" cmd_line 
        ${iomux}::puts "$magic $cmd_line"
        puts $fp_assert $line

        set buffer "$buffer\n$cmd_line"
        if [string equal "#cp%" $magic] {
           continue
        }

        regexp {\S+} $buffer cmd
          
	set rv [namespace eval harness::meta $buffer]
        # process cp line
        switch $cmd {
            {mkcp}    { }
            {excp}    { }
            {assert}  {
                if {$rv} { ${iomux}::puts "ASSERTION PASS"
                } else {   ${iomux}::puts "ASSERTION FAIL" }
            }
        }
        set buffer ""
    }
    close $fp
    close $fp_assert
    logger::info "------------- Assert -------------"
    #set harness::meta::assert_tcl ${assert.tcl}
    #harness::meta::trace
    #namespace eval harness::meta {source $assert_tcl}
}

